package hit.core;


import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

public class ItemFacadeTest {
	ItemFacade itemFacade;
	private HomeInventoryTracker hit;
	private StorageUnit storageUnit;
	private ProductGroup productGroup;
	private Product product;
	
	@Before
	public void setUp() {
		hit = HomeInventoryTracker.GetEmptyInstance();
		storageUnit = new StorageUnit("Cupboard");
		productGroup = new ProductGroup("Food");
		productGroup.SetParentContainer(storageUnit);
		productGroup.SetThreeMonth(new Size(1, Size.Unit.COUNT));
		hit.AddStorageUnit(storageUnit);
		storageUnit.AddProductGroup(productGroup);
		
		product = new Product();
		product.SetCreation(new Date());
		product.SetDescription("A candy bar");
		product.SetShelfLife(3);
		product.SetSize(new Size(4.0, Size.Unit.COUNT));
		product.SetThreeMonth(3);
		product.SetBarcode(new Barcode("885370395143"));
		
		itemFacade = new ItemFacade();
	}

	@After
	public void tearDown() {
		hit = null;
	}
	
	@Test
	public void TestAddItems() {
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(storageUnit));
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(productGroup));
		
		//add ten items to the StorageUnit
		Date entryDate = new Date();
		List<Item> modifiedItems = itemFacade.AddItems(product, 10, entryDate, storageUnit);
		
		//product group should still be empty
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(productGroup));
		
		//test that the size of the storageUnit is 10
		Set<Item> items = hit.GetItemIndex().GetItemsByProductContainer(storageUnit);
		assertEquals(10, items.size());
		
		//make sure the items look alright
		Iterator<Item> i = items.iterator();
		while (i.hasNext()) {
			Item item = i.next();
			assertEquals(product, item.GetProduct());
			assertTrue(Item.IsValid(item));
		}
		
		//make sure that the returned modifiedItems List contains the same Items as the hit
		for (Item item : modifiedItems) {
			assertTrue(items.contains(item));
		}
	}
	
	/**
	 * Relies on ItemFacade.AddItems()
	 * */
	@Test 
	public void TestRemoveItem() {
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(storageUnit));
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(productGroup));
		
		//add ten items to the StorageUnit
		Date entryDate = new Date();
		List<Item> modifiedItems = itemFacade.AddItems(product, 10, entryDate, storageUnit);
		
		//now remove each of those Items
		for (int i = 0; i < modifiedItems.size(); i++) {
			Item item = modifiedItems.get(i);
			Item removed = itemFacade.RemoveItem(item);
			
			//check that the removed item is the same
			assertEquals(item, removed);
			
			//check there are the right number of items in the hit
			assertEquals(modifiedItems.size() - 1 - i, 
					hit.GetItemIndex().GetItemsByProductContainer(storageUnit).size());
		}
	}
	
	@Test
	public void TestEditItem() {
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(storageUnit));
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(productGroup));
		
		//add an item to the StorageUnit
		Date entryDate = new Date();
		List<Item> modifiedItems = itemFacade.AddItems(product, 2, entryDate, storageUnit);
		
		//edit the first item in the list
		Item before = modifiedItems.get(0);
		Item after = new Item();
		after.SetBarcode(before.GetBarcode());
		after.SetContainer(before.GetContainer());
		after.SetEntry(before.GetEntry());
		after.SetProduct(before.GetProduct());
		
		//edit the entry date
		Date date = new Date();
		after.SetEntry(date);
		
		//now edit the item
		Item edited = itemFacade.EditItem(before, after);
		
		assertEquals(2, hit.GetItemIndex().GetItemsByProductContainer(storageUnit).size());
		assertEquals(after, edited);
		
		//test that we can get the new version of the item out of the item index
		edited = hit.GetItemIndex().GetItemByBarcode(after.GetBarcode());
		assertEquals(after, edited);
		assertEquals(date, edited.GetEntry());
	}
	
	@Test
	public void TestTransfer() {
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(storageUnit));
		assertEquals(null, hit.GetItemIndex().GetItemsByProductContainer(productGroup));
		
		StorageUnit unit2 = new StorageUnit("Pantry");
		hit.AddStorageUnit(unit2);
		
		//add an item to the StorageUnit
		Date entryDate = new Date();
		List<Item> modifiedItems = itemFacade.AddItems(product, 2, entryDate, storageUnit);
		
		//transfer the first item in the modifiedItems
		Item transferredItem = itemFacade.TransferItem(modifiedItems.get(0), unit2).get(0);
		assertEquals(modifiedItems.get(0), transferredItem);
		assertEquals(unit2, transferredItem.GetContainer());
		
		//make sure the sizes of the product containers is correct
		assertEquals(1, hit.GetItemIndex().GetItemsByProductContainer(storageUnit).size());
		assertEquals(1, hit.GetItemIndex().GetItemsByProductContainer(unit2).size());
	}
}
